from scipy.optimize import minimize
import numpy as np
#上述为调库操作，解释略

#题目如下：
#   min x1^2 + x2^2 + 3*x3^2 + 4*x4^2 + 2*x5^2 -8*x1 - 2*x2 - 3*x3 - x4 - 2*x5
#   s.t.x1 + x2 + x3 + x4 + x5 <=400;
#       x1 + 2*x2 + 2*x3 + x4 + 6*x5 <= 800;
#       2*x1 + x2 + 6*x3 <= 200;
#       x3 + x4 + 5*x5 <= 200;
#       0 <= xi <= 99,i=1,2,3,4,5
c1=np.array([1,1,3,4,2]); c2=np.array([-8,-2,-3,-1,-2])
#目标函数里的系数矩阵
A=np.array([[1,1,1,1,1],[1,2,2,1,6],
            [2,1,6,0,0],[0,0,1,1,5]])
#约束条件的系数矩阵
b=np.array([400,800,200,200])
#约束条件里的常数项矩阵
obj=lambda x: np.dot(-c1,x**2)+np.dot(-c2,x)
# np.dot()向量点乘或矩阵乘法，这里用它实现了目标函数的输入操作
#这里的x直接就是一个数组了。
cons={'type':'ineq','fun':lambda x:b-A@x}
#什么是ineq?eq就是equation，等式，那ineq就是不等式约束嘛
#要注意的是，约束条件要输入的为不小于0也就是大于等于0，所以用常数b,减去系数矩阵与x的积，A@x
#这里就是告诉程序，约束条件类型是不等式，方程式lambda x对应的约束条件
bd=[(0,99) for i in range(A.shape[1])]   # 生成决策向量界限的元组
#shape怎么用呢？
#我想读取矩阵第一个维度的长度，就是行数，那就用：矩阵.shape[0]
#如果想读取第二个维度的长度，就是列数，就用:矩阵.shape[1]
#这里有五个自变量，所以范围(0,99)应该被重复五次，故使用了一个循环，循环次数就是自变量的数目
#而自变量的数目又是系数矩阵的列数，所以自然就有了这个A.shape[1]
ini=[100,100,100,100,100]#给定初始值为五个自变量都是100
#实际上使用蒙特卡洛方法进行求解得到初始值最为合适。
res=minimize(obj,ini,constraints=cons,bounds=bd) #第2个参数为初值,这里采用的初值均为100
#这里才是真正的最后一步调用函数的操作
print(res.fun)#最小值
print(res.success)#求解状态
print(res.x)#最小值对应自变量取值
#这道题只能求得局部最优解
